<template>
  <div v-show="!route.query.url" class="backstage-container">
    <div class="backstage-content">
      <img alt="home_logo" class="home-logo" src="@/assets/img/index-img/home_logo.svg">
      <div class="sub-title-row">
        <h2>一站式侦查</h2>
        <h2>简洁高效</h2>
        <h2>预览下载</h2>
      </div>
      <searchInput/>
      <div v-if="$route.path === '/check' && !$route.query.url" class="hot-search">
        <img alt="hot-icon" height="32" src="@/assets/img/index-img/hot-icon.svg" width="32">
        <span>高频搜索：</span>
        <a-row :gutter="[30,0]">
          <a-col v-for="item in state.highUrlList" :key="item" class="hot-url-col" @click="fillUrl(item.homeUrl)">
            {{ item.homeUrl }}
          </a-col>
        </a-row>
      </div>
    </div>
  </div>
  <div v-show="route.query.url" class="check-container">
    <div class="search-content-box">
      <a-row class="search-content-card">
        <a-col :span="10">
          <div class="url-card-container">
            <a-skeleton :loading="state.searching" :paragraph="{ rows: 3, width: 70 }" active avatar>
              <div class="url-card-logo"></div>
              <div class="url-card-content">
                <h3>{{ !state.searching ? state.urlData?.at(0)?.icp?.data?.at(0)?.unitName : '' }}</h3>
                <p>{{ !state.searching ? state.urlData?.at(0)?.url : '' }}</p>
                <a-divider/>
                <a v-show="state.urlData?.at(0)?.url && !state.searching" @click.prevent="clickReport">点击举报</a>
              </div>
            </a-skeleton>
          </div>
        </a-col>
        <a-col :span="14">
          <div class="detect-card">
            <a-progress
                v-show="!state.searching"
                :format="percent=>`${percent}`"
                :percent="state.gradeNum"
                :stroke-color="{'0%': '#DA424F','50%': '#FA972D','100%':'#60B13C'}"
                trailColor="#E3E4FF"
                type="circle"
            />
            <div v-show="state.searching" class="progress-loading">
            </div>
            <a-skeleton :loading="state.searching" :paragraph="{ rows: 4, width: [70,200,200,200] }" :title="false"
                        active>
              <a-descriptions v-show="state.detectData.length > 0 " :column="2" class="detect-descript" title="域名检测">
                <a-descriptions-item v-for="item in state.detectData" :key="item">
                  <template #label>
                    <img v-show="item.code === 200" alt="detect-ok-white"
                         src="@/assets/img/check-img/detect-ok-white.svg">
                    <img v-show="item.code !== 200" alt="detect-failed-white"
                         src="@/assets/img/check-img/detect-failed-white.svg">
                    {{ item.title }}
                  </template>
                </a-descriptions-item>
              </a-descriptions>
            </a-skeleton>
            <a-skeleton :loading="state.searching" :paragraph="{ rows: 4, width: [70,200,200,200] }" :title="false"
                        active>
              <a-descriptions v-show="state.wenbenData.length > 0" :column="2" class="detect-descript" title="内容检测">
                <a-descriptions-item v-for="item in state.wenbenData" :key="item">
                  <template #label>
                    <img v-show="item.adopt" alt="detect-ok-white" src="@/assets/img/check-img/detect-ok-white.svg">
                    <img v-show="!item.adopt" alt="detect-failed-white"
                         src="@/assets/img/check-img/detect-failed-white.svg">
                    {{ item.text }}
                  </template>
                </a-descriptions-item>
              </a-descriptions>
            </a-skeleton>
          </div>
        </a-col>
      </a-row>
    </div>
    <div ref="displayAreaRef" class="display-area">
      <div ref="tabNavBoxRef" class="tab-nav-box">
        <div class="tab-nav-content">
          <a-tabs :activeKey="state.activeKey" @change="changeTab">
            <a-tab-pane key="0" tab="追踪还原">
            </a-tab-pane>
            <a-tab-pane key="1" :disabled="state.searching" tab="网页预览">
            </a-tab-pane>
          </a-tabs>
          <!-- 追踪还原 tab栏-->
          <div v-show="state.activeKey === '0'" ref="tab-oper" class="tab-operation">
            <div>
              <a-cascader v-model:value="state.defaultData" :allow-clear="false" :disabled="state.searching"
                          :field-names="{ value: 'id' }"
                          :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                          :options="state.uaOptions" placeholder="UA选择"
                          @change="changeUa"/>
            </div>
            <div class="tu-biao-area">
              <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         :placement="state.isFullScreen ? 'bottom' : 'top'"
                         :title="!state.searching ?`切换为${state.mouseType === 'left' ? '右':'左'}键拖拽` : ''"
                         overlayClassName="text-tip">
                <i v-show="state.mouseType === 'left'" :class="{'img-icon':true,'disabled-click':state.searching}"
                   @click="toggleMouse('right')">
                  <img alt="mouse-left" src="@/assets/img/check-img/mouse-left.svg"/>
                </i>
                <i v-show="state.mouseType === 'right'" :class="{'img-icon':true,'disabled-click':state.searching}"
                   @click="toggleMouse('left')">
                  <img alt="mouse-right" src="@/assets/img/check-img/mouse-right.svg"/>
                </i>
              </a-tooltip>
              <a-divider type="vertical"/>
              <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         :placement="state.isFullScreen ? 'bottom' : 'top'"
                         overlayClassName="text-tip" title="定位中心">
                <i :class="{'img-icon':true,'disabled-click':state.searching}" @click="locationGraph">
                  <img alt="dw" src="@/assets/img/check-img/dw.svg"/>
                </i>
              </a-tooltip>
              <a-divider type="vertical"/>
              <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         :placement="state.isFullScreen ? 'bottom' : 'top'"
                         overlayClassName="text-tip" title="缩小">
                <i :class="{'img-icon':true,'disabled-click':state.searching}" @click="changeZoom('minus')">
                  <img alt="minus" src="@/assets/img/check-img/minus.svg"/>
                </i>
              </a-tooltip>
              <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         :placement="state.isFullScreen ? 'bottom' : 'top'"
                         overlayClassName="text-tip" title="重置缩放">
                <span class="percentage-num" @click="resetScale">{{ state.mindMapZoom }}%</span>
              </a-tooltip>
              <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         :placement="state.isFullScreen ? 'bottom' : 'top'"
                         overlayClassName="text-tip" title="放大">
                <i :class="{'img-icon':true,'disabled-click':state.searching}" @click="changeZoom('add')">
                  <img alt="add" src="@/assets/img/check-img/add.svg"/>
                </i>
              </a-tooltip>
              <a-divider type="vertical"/>
              <a-tooltip overlayClassName="text-tip" placement="top" title="全屏">
                <i v-show="!state.isFullScreen" :class="{'img-icon':true,'disabled-click':state.searching}"
                   @click="fullScreen">
                  <img alt="icon_fangda" src="@/assets/img/check-img/icon_fangda.svg"/>
                </i>
              </a-tooltip>
              <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         overlayClassName="text-tip"
                         placement="bottom" title="退出全屏">
                <i v-show="state.isFullScreen" :class="{'img-icon':true,'disabled-click':state.searching}"
                   @click="closeFullScreen">
                  <img alt="close-fd" class="close-screen-img" src="@/assets/img/check-img/icon_tuichuquanping.svg"/>
                </i>
              </a-tooltip>
            </div>

            <div class="share-area">
              <a-popover v-model:visible="state.showExport"
                         :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         overlayClassName="export-menu"
                         placement="bottom" title="导出文档">
                <template #content>
                  <div class="export-btn-box">
                    <a-button @click="exportFile('png')">
                      <img alt="png-icon.png" src="@/assets/img/check-img/png-icon.png"/>
                      png格式文档
                    </a-button>
                    <a-button type="primary" @click="exportFile('pdf')">
                      <img alt="pdf-icon.png" src="@/assets/img/check-img/pdf-icon.png"/>
                      pdf格式文档
                    </a-button>
                  </div>
                </template>
                <img :class="{'disabled-click':state.searching}" alt="icon_xizai"
                     src="@/assets/img/check-img/icon_xizai.svg">
              </a-popover>
              <a-popover v-model:visible="state.showShare"
                         :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                         overlayClassName="share-menu"
                         placement="bottom" title="分享文档">
                <template #content>
                  <a-descriptions layout="horizontal">
                    <a-descriptions-item label="链接">{{ state.shareLink }}</a-descriptions-item>
                  </a-descriptions>
                  <a-button type="primary" @click="copySome(state.shareLink)">复制链接</a-button>
                </template>
                <a-button :class="{'share-btn':true,'disabled-click':state.searching}" shape="round" type="primary">
                  <template #icon>
                    <img alt="icon_fenxiang" src="@/assets/img/check-img/icon_fenxiang.svg"/>
                    分享
                  </template>
                </a-button>
              </a-popover>
            </div>
          </div>
          <!-- 网页预览-->
          <div v-show="state.activeKey == '1'" ref="tab-page-prev" class="tab-page-preview">
            <a-tooltip overlayClassName="text-tip" placement="top" title="全屏">
              <i v-show="!state.isFullScreen" :class="{'img-icon':true,'disabled-click':state.searching}"
                 @click="fullScreen">
                <img alt="icon_fangda" src="@/assets/img/check-img/icon_fangda.svg"/>
              </i>
            </a-tooltip>
            <a-tooltip :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                       overlayClassName="text-tip"
                       placement="bottom" title="退出全屏">
              <i v-show="state.isFullScreen" :class="{'img-icon':true,'disabled-click':state.searching}"
                 @click="closeFullScreen">
                <img alt="close-fd" class="close-screen-img" src="@/assets/img/check-img/icon_tuichuquanping.svg"/>
              </i>
            </a-tooltip>
            <a-button v-show="state.delMaskLayer" shape="round" style="margin-right: 10px;" @click="cancelDel">
              取消删除
            </a-button>
            <a-button shape="round" type="primary" @click="del">
              批量删除
            </a-button>
          </div>
        </div>
      </div>
      <a-spin :spinning="state.searching" tip="正在检测中，请耐心等候...">
        <a-dropdown v-model:visible="state.showRightMenu"
                    :getPopupContainer="triggerNode => triggerNode.parentNode || document.body"
                    overlayClassName="right-menu"
                    placement="bottomLeft" trigger="contextmenu">
          <div v-show="state.activeKey == '0'" ref="mindContentRef" class="mind-map-content">
            <div ref="mindboxRef" class="mind-map-box">
              <div id="mind-map-container" ref="mindMapRef"
                   :style="{
                    width: state.mindMapWidth,
                    height: state.mindMapHeight,
                    transform: 'scale('+state.touchBoxScale+')'
                  }">
              </div>
            </div>
          </div>
          <template #overlay>
            <a-menu @click="state.showRightMenu = false">
              <a-menu-item v-if="!state.isFullScreen" key="fullscreen" @click="fullScreen">
                <fullscreen-outlined/>
                全屏
              </a-menu-item>
              <a-menu-item v-else key="closefullscreen" @click="closeFullScreen">
                <fullscreen-exit-outlined/>
                退出全屏
              </a-menu-item>
              <a-menu-item key="location" @click="locationGraph">
                <aim-outlined/>
                定位中心
              </a-menu-item>
              <a-menu-item key="refresh" @click="refresh">
                <redo-outlined/>
                重新加载
              </a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
        <div v-show="state.activeKey == '0'" class="small-map-container">
          <canvas id="small-map" ref="smallMapRef"></canvas>
          <div id="view-port" ref="viewPortRef"></div>
        </div>
      </a-spin>
      <div v-show="state.activeKey == '1'" ref="previewBoxRef" class="preview-box">
        <Preview ref="previewCom" :delMaskLayer="state.delMaskLayer"
                 :isTrue="state.isTrue" :options="state.uaOptions"
                 :region="state.regionValue" :url="state.webPage" @changeDelMaskLayer="state.delMaskLayer=false"
                 @changeMaskLayer="state.delMaskLayer=true" @updateIsTrue="(data)=>state.isTrue = data"/>
      </div>
    </div>
  </div>
</template>

<script setup>
import Preview from '@/components/preview'
import searchInput from '@/components/searchInput'
import {RedoOutlined, AimOutlined, FullscreenOutlined, FullscreenExitOutlined} from '@ant-design/icons-vue'
import {reactive, getCurrentInstance, onMounted, onUnmounted, nextTick, watch} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import {useStore} from 'vuex'
import {trackIndex, uaRequest, highUrl} from '@/axios'
import TCaptcha from '@/plugin/TCaptcha'
import jsmind from '@/plugin/jsmind'
import '@/assets/css/jsmind.css'
import axios from 'axios'
import html2canvas from 'html2canvas'
import JSPDF from 'jspdf'

const store = useStore()
const tcaptcha = new TCaptcha()
const route = useRoute()
const router = useRouter()
const {proxy} = getCurrentInstance()

const state = reactive({
  delMaskLayer: false, // 删除遮罩层
  activeKey: '0',
  uaOptions: [], // UA下拉框数据
  defaultData: [1, 14, 16], // UA选择数据
  isTrue: true,
  webPage: '',
  regionValue: '',
  urlData: [],
  gradeNum: 100,
  mouseType: 'left',
  mindMapZoom: 100,
  isFullScreen: false,
  detectData: [],
  searching: false,
  showExport: false,
  showShare: false,
  showRightMenu: false,
  wenbenData: [],
  mindMapWidth: '',
  mindMapHeight: '',
  shareLink: window.location.href,
  bannedWord: ['暴恐违禁', '文本色情', '政治敏感', '恶意推广', '低俗辱骂'],
  differX: 8750,
  differY: 9400,
  touchBoxScale: 1,
  jmActualWidth: 0,
  hmargin: 80,
  vmargin: 50,
  highUrlList: []
})

const getHighUlr = async () => {
  const res = await highUrl()
  res.code === 0 ? state.highUrlList = res.data : proxy.$message.error(res.msg)
}
!route.query.url ? getHighUlr() : ''
watch(() => route.query.url, (newVal, oldVal) => !newVal ? getHighUlr() : '')

const fillUrl = url => store.state.queryForm.url = `http://${url}`

const changeUa = val => {
  // if(!store.state.userInfo.mobile && store.state.isLogin) return store.commit('checkIsBindMobile')
  state.defaultData = val
  locationGraph()
  searchUrl()
}

const changeTab = key => {
  state.activeKey = key
  nextTick(() => {
    if (key == 0) {
      window.scrollTo(0, state.differY)
      displayArea.scrollTo(0, state.differY)
      mindContent.scrollTo(state.differX, 0)
    } else {
      window.scrollTo(0, 0)
      displayArea.scrollTo(0, 0)
    }
  })
}

const del = () => {
  state.delMaskLayer = !state.delMaskLayer
  proxy.$refs.previewCom.delUa()
}

const cancelDel = () => {
  state.delMaskLayer = !state.delMaskLayer
  proxy.$refs.previewCom.cancelPreDel()
}

const clickReport = () => {
  if (state.urlData.length > 1) {
    jm.expand_node('1-1')
    jm.expand_node('1-1-5')
  } else {
    jm.expand_node('1-5')
  }
}

const buildTree = (arr) => {
  let tree = []
  let map = arr.reduce((pre, cur) => {
    pre[cur.id] = cur
    return pre
  }, {})

  for (let item of arr) {
    if (item.superior === 0) {
      tree.push(item)
      continue
    }
    if (item.superior in map) {
      const parent = map[item.superior]
      parent.children = parent.children || []
      parent.children.push(item)
    }
  }
  return tree
}

route.query.url ? uaRequest('/getua').then(res => state.uaOptions = buildTree(JSON.parse(JSON.stringify(res)))) : ''

const copySome = content => {
  let oInput = document.createElement('input')
  oInput.value = content
  oInput.style.visibility = '0'
  document.body.appendChild(oInput)
  oInput.select()
  document.execCommand('Copy')
  oInput.remove()
  proxy.$message.success('已复制分享链接到剪切板。')
}
// 思维导图初始数据
const mindMapData = reactive({
  meta: {
    name: '',
    author: '',
    version: ''
  },
  format: 'node_tree',
  data: {}
})
// 查询链接
const searchUrl = () => {
  if (route.query.url) {
    document.body ? document.body.style.overflow = 'hidden' : ''
    displayArea ? displayArea.style.overflow = 'hidden' : ''
    store.state.queryForm.url = route.query.url
    store.state.queryForm.ua = state.defaultData[2]
    mindMapData.data = {}
    state.wenbenData = []
    state.detectData = []
    state.urlData = []
    state.searching = true
    state.gradeNum = 100
    trackIndex(store.state.queryForm).then(async res => {
      if (res.code === -2) {
        state.searching = false
        tcaptcha.getTCaptcha(async data => {
          data.CaptchaCode === 1 ? await searchUrl() : proxy.$message.error('验证失败，请重试。')
        })
      } else if (res.code === 200) {
        for (let key in res.data) {
          res.data[key].url = key
          res.data[key].icp = JSON.parse(res.data[key].icp)
          state.urlData.push(res.data[key])
        }
        state.wenbenData = [
          {text: '暴恐违禁', adopt: true},
          {text: '文本色情', adopt: true},
          {text: '政治敏感', adopt: true},
          {text: '恶意推广', adopt: true},
          {text: '低俗辱骂', adopt: true}
        ]
        if (res.wenben?.conclusion === '不合规') {
          state.wenbenData.forEach(text => {
            res.wenben.data.forEach(item => {
              if (item.msg.indexOf(text.text) > -1) {
                text.adopt = false
                state.gradeNum -= 10
              }
            })
          })
        }
        if (state.urlData.length === 1) {
          const res = await secondaryQuery(state.urlData[0].url)
          if (res.code === 200) {
            mindMapData.data = {
              id: '1',
              topic: state.urlData[0].url,
              children: getDetails('1', res)
            }
            initMindMap()
          } else {
            proxy.$message.error(res.msg)
            state.searching = false
          }
        } else if (state.urlData.length === 2) {
          axios.all([secondaryQuery(state.urlData[0].url), secondaryQuery(state.urlData[1].url)])
              .then(axios.spread((res1, res2) => {
                mindMapData.data = {
                  id: '1',
                  topic: state.urlData[0].url,
                  children: [
                    {
                      id: '1-1',
                      topic: '入口层：' + state.urlData[0].url,
                      expanded: false,
                      children: getDetails('1-1', res1),
                      'background-color': '#483CFF',
                      'foreground-color': '#FFFFFF',
                      'border-color': '#483CFF',
                    },
                    {
                      id: '1-2',
                      topic: '落地页：' + state.urlData[1].url,
                      expanded: false,
                      children: getDetails('1-2', res2),
                      'background-color': '#60B13C',
                      'foreground-color': '#FFFFFF',
                      'border-color': '#60B13C',
                    },
                  ]
                }
                initMindMap()
              }))
        } else {
          axios.all(state.urlData.map(item => secondaryQuery(item.url))).then(res => {
            let urlArr = []
            res.forEach((data, index) => {
              if (index !== 0 && index !== res.length - 1) {
                if (res[index]?.code === 200) {
                  urlArr.push({
                    id: `1-2-${index}`,
                    topic: state.urlData[index].url,
                    expanded: false,
                    children: getDetails(`1-2-${index}`, res[index]),
                    'background-color': '#FFFBE5',
                    'foreground-color': '#FA972D',
                    'border-color': '#FA972D',
                  })
                }
              }
            })
            mindMapData.data = {
              id: '1',
              topic: state.urlData[0].url,
              children: [
                {
                  id: '1-1',
                  topic: '入口层：' + state.urlData[0].url,
                  expanded: false,
                  children: getDetails('1-1', res[0]),
                  'background-color': '#483CFF',
                  'foreground-color': '#FFFFFF',
                  'border-color': '#483CFF',
                },
                {
                  id: '1-2',
                  topic: '涉及链接（中转层）：',
                  expanded: false,
                  children: urlArr,
                  'background-color': '#FA972D',
                  'foreground-color': '#FFFFFF',
                  'border-color': '#FA972D',
                },
                {
                  id: '1-3',
                  topic: '落地页：' + state.urlData.at(-1).url,
                  expanded: false,
                  children: getDetails('1-3', res.at(-1)),
                  'background-color': '#60B13C',
                  'foreground-color': '#FFFFFF',
                  'border-color': '#60B13C',
                }
              ]
            }
            initMindMap()
          })
        }
        state.urlData[0].icp.code !== 200 ? state.gradeNum -= 5 : ''
        state.detectData.unshift({title: 'icp域名检测', ...state.urlData[0].icp})
        Object.keys(res).forEach(item => {
          if (['dy', 'qihu360', 'qq', 'vx'].includes(item)) {
            let title = ''
            item === 'dy' ? title = '抖音' : ''
            item === 'qihu360' ? title = '360' : ''
            item === 'qq' ? title = 'qq' : ''
            item === 'vx' ? title = '微信' : ''
            res[item].code != 200 ? state.gradeNum -= 5 : ''
            state.detectData.push({title: title + '域名检测', ...res[item]})
          }
        })
      } else {
        proxy.$message.error(typeof res === 'string' ? unescape((JSON.parse(res).msg).replace(/\\u/gi, '%u')) : res.msg)
        state.searching = false
        router.replace('/check', {query: {}})
      }
    })
  }
}
searchUrl()
const secondaryQuery = url => {
  let newFormData = JSON.parse(JSON.stringify(store.state.queryForm))
  newFormData.type = 2
  newFormData.url = url
  return trackIndex(newFormData).then(res => {
    if (res.code === -2) {
      tcaptcha.getTCaptcha(async data => {
        data.CaptchaCode === 1 ? await secondaryQuery() : proxy.$message.error('验证失败，请重试。')
      })
    } else if (res.code === 200) {
      return res
    } else {
      proxy.$message.error(res.msg)
      state.searching = false
    }
  })
}
// 初始化思维导图
const initMindMap = () => {
  jm.show(mindMapData)
  state.mindMapWidth = jmnodes.style.width
  state.mindMapHeight = jmnodes.style.height
  mindBox.style.width = '20000px'
  mindBox.style.height = '20000px'
  mindMap.style.transform = `scale${state.touchBoxScale}`
  window.scrollTo(0, state.differY)
  mindContent.scrollTo(state.differX, 0)
  document.body.style.overflow = 'unset'
  displayArea.style.overflow = 'auto'
  proxy.$message.success('检测成功')
  handleNodeStyle()
  renderMiniMap()
  state.searching = false
  const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
  const observer = new MutationObserver(mutations => {
    state.mindMapWidth = jmnodes.style.width
    state.mindMapHeight = jmnodes.style.height
    renderMiniMap()
  })
  observer.observe(jmnodes, {
    subtree: true,
    attributeFilter: ['style']
  })
  setTimeout(()=>{
    locationGraph()
  },200)
}
// 处理节点样式
const handleNodeStyle = () => {
  jm.enable_edit()
  const jmnodeList = Array.from(document.querySelectorAll('jmnode'))
  const urlDataLength = state.urlData.length
  jmnodeList.forEach((item, index) => {
    const nodeid = item.getAttribute('nodeid')
    const nodeParent = jm.get_node(nodeid).parent
    const nodeThreeStr = item.innerText.substr(0, 3)
    if (index > 0 && (nodeParent?.parent?.topic !== '内容检测' || nodeThreeStr === '置信度') && nodeParent?.topic !== '安全检测分值') {
      if (urlDataLength > 1) {
        if (nodeid.length > 3) {
          const threeStr = nodeid.substr(0, 3)
          if (threeStr === '1-1') {
            jm.set_node_color(nodeid, '#EFF4FF', nodeid.length === 5 ? '#483CFF' : '', '#483CFF')
          }
          if ((urlDataLength === 2 && threeStr === '1-2') || (urlDataLength >= 3 && threeStr === '1-3')) {
            jm.set_node_color(nodeid, '#F4FFEC', nodeid.length === 5 ? '#60B13C' : '', '#60B13C')
          }
          if (urlDataLength >= 3 && threeStr === '1-2') {
            jm.set_node_color(nodeid, '#FFFBE5', nodeid.length === 7 ? '#FA972D' : '', '#FA972D')
          }
        }
      } else {
        jm.set_node_color(nodeid, '#EFF4FF', nodeid.length === 3 ? '#483CFF' : '', '#483CFF')
      }
      item.querySelector('a') ? item.querySelector('a').style.color = item.style.borderColor : ''
    }
  })
  jm.disable_edit()
}
// 加载小地图
const renderMiniMap = () => {
  const smallMap = proxy.$refs.smallMapRef,
      miniMap = {
        ctx: smallMap.getContext('2d'),
        minLeft: null,
        maxRight: null,
        minTop: null,
        maxBottom: null,
        nodeLocateList: [],
        nodeChildList: Array.from(jmnodes.childNodes),
      }
  miniMap.ctx.clearRect(0, 0, smallMap.width, smallMap.height)
  miniMap.nodeChildList.forEach((item, index) => {
    if (item.style.visibility === 'visible' && item.style.display !== 'none' && item.localName === 'jmnode') {
      const clientRect = item.getBoundingClientRect()
      if (index === 0) {
        miniMap.minLeft = clientRect.left
        miniMap.maxRight = clientRect.right
        miniMap.minTop = clientRect.top
        miniMap.maxBottom = clientRect.bottom
      }
      clientRect.top < miniMap.minTop ? miniMap.minTop = clientRect.top : ''
      clientRect.right > miniMap.maxRight ? miniMap.maxRight = clientRect.right : ''
      clientRect.bottom > miniMap.maxBottom ? miniMap.maxBottom = clientRect.bottom : ''
      const x = item.offsetLeft, y = item.offsetTop, w = item.offsetWidth, h = item.offsetHeight
      miniMap.nodeLocateList.push({x, y, w, h})
    }
    if (index + 1 === miniMap.nodeChildList.length) {
      state.jmActualWidth = miniMap.minLeft >= 0 ? miniMap.maxRight - miniMap.minLeft : miniMap.maxRight + Math.abs(miniMap.minLeft)
      const jmActualHeight = miniMap.minTop >= 0 ? miniMap.maxBottom - miniMap.minTop : miniMap.maxBottom + Math.abs(miniMap.minTop)
      const xPt = (smallMap.width / state.jmActualWidth) * 0.8, yPt = smallMap.height / jmnodes.offsetHeight
      viewPort.style.width = state.jmActualWidth * xPt + 'px'
      viewPort.style.height = miniMap.nodeLocateList.length <= 3 ? jmActualHeight + 'px' : jmActualHeight * yPt + 20 + 'px'
      viewPort.style.left = state.hmargin * xPt + 'px'
      viewPort.style.top = state.vmargin * yPt + 'px'
      miniMap.nodeLocateList.forEach((item, index) => {
        const {x, y, w, h} = item
        miniMap.ctx.fillStyle = index === 0 ? '#483CFF' : '#cecece'
        miniMap.ctx.fillRect(x * xPt, y * yPt, w * xPt, h * yPt)
      })
    }
  })
}
// 处理思维导图详细数据
const getDetails = (id, res) => {
  let index = 0, index1 = 0, index2 = 0, index3 = 0, index4 = 0, index5 = 0, wenben = [], icpAll = [], jiedian = [],
      cname = [], grade = 100
  if (res.data.wenben?.conclusion === '不合规') {
    res.data.wenben.data.forEach(item => {
      state.bannedWord.forEach(text => {
        if (item.msg.indexOf(text) > -1) {
          wenben.push({
            id: `${id}-${index}-${index1}-${index2 += 1}`,
            topic: text,
            expanded: true,
            children: [
              {
                id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
                topic: `状态：不通过`,
                'background-color': '#FFF0F0',
                'foreground-color': '#DA424F',
                'border-color': '#DA424F',
              },
              {
                id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
                topic: `置信度：${item.hits[0].probability}`,
              },
              {
                id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
                topic: `违禁词：${item.hits[0].words}`,
                'background-color': '#FFF0F0',
                'foreground-color': '#DA424F',
                'border-color': '#DA424F',
              },
            ]
          })
          grade -= 10
        } else {
          wenben.push({
            id: `${id}-${index}-${index1}-${index2 += 1}`,
            topic: text,
            expanded: true,
            children: [
              {
                id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
                topic: `状态：通过`,
                'background-color': '#F4FFEC',
                'foreground-color': '#60B13C',
                'border-color': '#60B13C',
              },
              {
                id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
                topic: `置信度：0.00`,
              }
            ]
          })
        }
      })
    })
  } else {
    state.bannedWord.forEach(text => {
      wenben.push({
        id: `${id}-${index}-${index1}-${index2 += 1}`,
        topic: text,
        expanded: true,
        children: [
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `状态：通过`,
            'background-color': '#F4FFEC',
            'foreground-color': '#60B13C',
            'border-color': '#60B13C',
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `置信度：1.00`,
          }
        ]
      })
    })
  }
  if (res.data.cdn.Address.length > 0) {
    res.data.cdn.Address.forEach((item, i) => {
      jiedian.push({
        id: `${id}-${index}-${index1}-${index2}-${index3}-${index4 += 1}`,
        topic: res.data.cdn.Name[i],
        expanded: true,
        children: [
          {
            id: `${id}-${index}-${index1}-${index2}-${index3}-${index4}-${index5 += 1}`,
            topic: item,
          }
        ]
      })
    })
  }
  if (res.data.cdn.Cname.length > 0) {
    res.data.cdn.Cname.forEach(item => {
      cname.push({
        id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
        topic: `域名：${item[0]}`,

        children: [
          {
            id: `${id}-${index}-${index1}-${index2}-${index3}-${index4 += 1}`,
            topic: `提供商：${item[1]}`,

          }
        ]
      })
    })
  }
  Object.keys(res.data).forEach(item => {
    if (['dy', 'qihu360', 'qq', 'vx', 'icp'].includes(item)) {
      res.data[item].code !== 200 ? grade -= 5 : ''
    }
  })
  if (res.data.icp_all.code === 200) {
    icpAll = res.data.icp_all.data.map(item => {
      return {
        id: `${id}-${index}-${index1}-${index2 += 1}`,
        topic: `网站域名：<a href="${item.domain?.indexOf('http') > -1 ? item.domain : 'http://' + item.domain}" target="_blank">${item.domain}</a>`,
        expanded: true,
        children: [
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `网站备案/许可证号：${item.serviceLicence}`,
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `网站名称：${item.serviceName || '未知'}`,
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: item.homeUrl ? `网站首页地址：<a href="${item.homeUrl?.indexOf('http') > -1 ? item.homeUrl : 'http://' + item.homeUrl}" target="_blank">${item.homeUrl}</a>` : '网站首页地址：未知',
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `审核通过时间：${item.updateRecordTime}`,

          }
        ]
      }
    })
  } else if (res.data.icp_all.length > 0) {
    icpAll = res.data.icp_all.map(item => {
      return {
        id: `${id}-${index}-${index1}-${index2 += 1}`,
        topic: `网站域名：<a href="${item?.domain?.indexOf('http') > -1 ? item?.domain : 'http://' + item?.domain}" target="_blank">${item?.domain}</a>`,
        expanded: true,
        children: [
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `网站备案/许可证号：${item?.serviceLicence}`,
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `网站名称：${item.serviceName || '-'}`,
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: item.homeUrl ? `网站首页地址：<a href="${item.homeUrl?.indexOf('http') > -1 ? item.homeUrl : 'http://' + item.homeUrl}" target="_blank">${item.homeUrl}</a>` : '网站首页地址：-',
          },
          {
            id: `${id}-${index}-${index1}-${index2}-${index3 += 1}`,
            topic: `审核通过时间：${item?.updateRecordTime}`,

          }
        ]
      }
    })
  }
  return [
    {
      id: `${id}-${index += 1}`,
      topic: '域名注册信息',
      expanded: false,
      children: [
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `注册商：${res.data.whois.Registrar || '-'}`,
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `联系人：${res.data.whois.Registrant || '-'}`,
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `更新时间：${res.data.whois.update_time || '-'}`,
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `创建时间：${res.data.whois.create_time || '-'}`,
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `过期时间：${res.data.whois.Expiration_Date || '-'}`,
        },
        // {
        //   id: `${id}-${index}-${index1 += 1}`,
        //   topic: `公司`,
        // },
        // {
        //   id: `${id}-${index}-${index1 += 1}`,
        //   topic: `域名服务器`,
        // },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `DNS：${res.data.whois.Name_Server || '-'}`,
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `状态：${res.data.whois.Domain_Status || '-'}`,
        },
        // {
        //   id: `${id}-${index}-${index1 += 1}`,
        //   topic: `注册所有地`,
        // },
      ]
    },
    {
      id: `${id}-${index += 1}`,
      topic: '备案信息',
      expanded: false,
      children: [
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '基本信息',
          expanded: false,
          children: [
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `主办单位名称：${res.data.icp.unitName || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `主办单位性质：${res.data.icp.natureName || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `网站备案/许可证号：${res.data.icp.serviceLicence || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `网站名称：${res.data.icp.serviceName || '-'}`,
            },
            // {
            //   id: `${id}-${index}-${index1}-${index2 +=1}`,
            //   topic: `网站负责人`,
            // },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `网站首页网址：${res.data.icp.homeUrl || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `网站类型：${res.data.wangan?.type || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `审核时间：${res.data.icp.updateRecordTime || '-'}`,
            }
          ]
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '网安备案',
          expanded: false,
          children: [
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `网安备案号：${res.data.wangan?.BeianName || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `备案地公安机关：${res.data.wangan?.BeianAddr || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `联网备案时间：${res.data.wangan?.BeianTime || '-'}`,
            }
          ]
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '企业工商信息',
          expanded: false,
          children: [
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `公司状态：${res.data.business.Status || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `公司类型：${res.data.business.EconKind || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `注册资本：${res.data.business.RegistCapi || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `注册时间：${res.data.business.RegistCapi || '-'}`,
            },
            // {
            //   id: `${id}-${index}-${index1}-${index2 += 1}`,
            //   topic: '工商注册号：',
            // },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `所属行业：${(res.data?.business?.RegistCapi)?.split('\t')?.at(0) || '-'}`,
            },
            // {
            //   id: `${id}-${index}-${index1}-${index2 +=1}`,
            //   topic: '纳税人识别号',
            // },
            // {
            //   id: `${id}-${index}-${index1}-${index2 +=1}`,
            //   text: '核准日期',
            // },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `注册地址：${res.data?.business?.Address || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `经营范围：${res.data?.business?.Industry?.Industry || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `法定代表人：${res.data?.business?.OperName || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `邮箱：${res.data?.business?.Email || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `联系方式：${res.data?.business?.ContactNumber || '-'}`,
            }
          ]
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '同一主办单位的备案网站',
          expanded: false,
          children: [...icpAll]
        }
      ]
    },
    // {
    //   id: `${id}-${index += 1}`,
    //   topic: '服务器信息',
    //   expanded: false,
    //   children: []
    // },
    {
      id: `${id}-${index += 1}`,
      topic: 'cdn信息',
      expanded: false,
      children: [
        {
          id: `${id}-${index}-${index1}-${index2 += 1}`,
          topic: 'CNAME信息',
          expanded: false,
          children: [...cname]
        },
        {
          id: `${id}-${index}-${index1}-${index2 += 1}`,
          topic: '节点信息',
          expanded: false,
          children: [...jiedian]
        }
      ]
    },
    {
      id: `${id}-${index += 1}`,
      topic: '安全检测',
      expanded: false,
      children: [
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '域名检测',
          expanded: false,
          children: [
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `icp域名检测：${res.data.icp.code === 200 ? `<span class="success-text">正常</span>` : `<span class="danger-text">${res.data.icp.msg}</span>`}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `qq域名检测：${res.data.qq.code === 200 ? `<span class="success-text">${res.data.qq.msg}</span>` : `<span class="danger-text">${res.data.qq.msg}</span>` || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `微信域名检测：${res.data.vx.code === 200 ? `<span class="success-text">${res.data.vx.msg}</span>` : `<span class="danger-text">${res.data.vx.msg}</span>` || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `360域名检测：${res.data.qihu360.code === 200 ? `<span class="success-text">${res.data.qihu360.msg}</span>` : `<span class="danger-text">${res.data.qihu360.msg}</span>` || '-'}`,
            },
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `抖音域名检测：${res.data.douyin.code === 200 ? `<span class="success-text">${res.data.douyin.msg}</span>` : `<span class="danger-text">${res.data.douyin.msg}</span>` || '-'}`,
            }
          ]
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '内容检测',
          expanded: false,
          children: [...wenben]
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: '安全检测分值',
          expanded: false,
          children: [
            {
              id: `${id}-${index}-${index1}-${index2 += 1}`,
              topic: `${grade}分`,
              'background-color': '#FFFBE5',
              'foreground-color': '#FA972D',
              'border-color': '#FA972D',
            }
          ]
        }
      ]
    },
    {
      id: `${id}-${index += 1}`,
      topic: '举报入口',
      expanded: false,
      children: [
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `<a href="https://fqlq4dbcak.feishu.cn/share/base/shrcnut03QZKmankyMMI4VbZWEc" target="_blank">代举报（本公司受理）</a>`,
          expanded: true
        },
        {
          id: `${id}-${index}-${index1 += 1}`,
          topic: `<a href="${window.location.origin}/help" target="_blank">其他举报入口</a>`,
          expanded: true
        }
      ]
    }
  ]
}

let jm, mindMap, mindBox, mindContent, tabNavBox, displayArea, viewPort, jmInner, jmnodes, previewBox
onMounted(() => {
  if (route.query.url) {
    const app = document.querySelector('#app')
    displayArea = proxy.$refs.displayAreaRef
    mindContent = proxy.$refs.mindContentRef
    mindBox = proxy.$refs.mindboxRef
    mindMap = proxy.$refs.mindMapRef
    tabNavBox = proxy.$refs.tabNavBoxRef
    viewPort = proxy.$refs.viewPortRef
    previewBox = proxy.$refs.previewBoxRef
    const progressText = document.querySelector('.ant-progress-text')
    const score = document.createElement('span')
    score.innerText = '分'
    progressText.append(score)
    document.body.style.overflow = 'hidden'
    displayArea.style.overflow = 'hidden'
    jm = new jsmind({
      container: mindMap,
      editable: false,
      theme: 'custom',
      mode: 'side',
      support_html: true,
      view: {
        engine: 'canvas',     // 思维导图各节点之间线条的绘制引擎
        hmargin: state.hmargin,         // 思维导图距容器外框的最小水平距离
        vmargin: state.vmargin,         // 思维导图距容器外框的最小垂直距离
        line_width: 0.3,        // 思维导图线条的粗细
        line_color: '#999999' // 思维导图线条的颜色
      },
      layout: {
        hspace: 50,           // 节点之间的水平间距
        vspace: 20,           // 节点之间的垂直间距
        pspace: 13,           // 节点与连接线之间的水平间距（用于容纳节点收缩/展开控制器）
      },
      shortcut: {
        enable: false          // 是否启用快捷键
      }
    })
    jmnodes = document.querySelector('jmnodes')
    jmInner = document.querySelector('.jsmind-inner')
    displayArea.addEventListener('mousewheel', function (event) {
      if (event.ctrlKey === true || event.metaKey) {
        if (event.deltaY > 0 && state.touchBoxScale > 0.5 && state.mindMapZoom > 50) {
          state.mindMapZoom -= 10
          state.touchBoxScale -= 0.1
          mindMap.style.transform = `scale${state.touchBoxScale}`
        } else if (event.deltaY < 0 && state.touchBoxScale < 2 && state.mindMapZoom < 200) {
          state.mindMapZoom += 10
          state.touchBoxScale += 0.1
          mindMap.style.transform = `scale${state.touchBoxScale}`
        }
        event.preventDefault()
      }
    }, {
      passive: false,
      capture: true
    })

    const dragMove = (element, type) => {
      element.addEventListener('mousedown', function (e) {
        jm.select_clear()
        const confirmMindBox = (e.button === 0 && state.mouseType === 'left') || (e.button === 2 && state.mouseType === 'right')
        if ((confirmMindBox && type === 'mindBox') || (e.button === 0 && type === 'viewPort')) {
          const down = {
            x: e.clientX,
            y: e.clientY,
            scrollLeft: mindContent.scrollLeft,
            scrollTop: !state.isFullScreen ? document.documentElement.scrollTop : displayArea.scrollTop,
            oldLeft: JSON.parse(JSON.stringify(viewPort.style.left)),
            oldTop: JSON.parse(JSON.stringify(viewPort.style.top))
          }
          type === 'mindBox' && !state.showRightMenu ? app.style.cursor = '-webkit-grabbing' : ''
          document.onmousemove = function (event) {
            if (type === 'mindBox') {
              state.differX = down.scrollLeft - (event.clientX - down.x)
              state.differY = down.scrollTop - (event.clientY - down.y)
            } else if (type === 'viewPort') {
              viewPort.style.left = parseFloat(down.oldLeft) + (event.clientX - down.x) + 'px'
              viewPort.style.top = parseFloat(down.oldTop) + (event.clientY - down.y) + 'px'
              state.differX = down.scrollLeft + (event.clientX - down.x) * 2
              state.differY = down.scrollTop + (event.clientY - down.y) * 2
            }
            app.style.userSelect = 'none'
            !state.isFullScreen ? window.scrollTo(0, state.differY) : displayArea.scrollTo(0, state.differY)
            mindContent.scrollTo(state.differX, 0)
          }
          document.onmouseup = function () {
            this.onmousemove = this.onmouseup = this.oncontextmenu = null
            app.style.userSelect = 'unset'
            if (type === 'viewPort') {
              viewPort.style.left = down.oldLeft
              viewPort.style.top = down.oldTop
            } else {
              app.style.cursor = 'default'
            }
          }
        }
      })
    }

    dragMove(mindBox, 'mindBox')
    dragMove(viewPort, 'viewPort')

    document.addEventListener('scroll', scrollFn, true)
    document.addEventListener('fullscreenchange', () => document.fullscreenElement ? fullScreen() : closeFullScreen())
    document.addEventListener('msfullscreenchange', () => document.msFullscreenElement ? fullScreen() : closeFullScreen())
    document.addEventListener('mozfullscreenchange', () => document.mozFullScreen ? fullScreen() : closeFullScreen())
    document.addEventListener('webkitfullscreenchange', () => document.webkitIsFullScreen ? fullScreen() : closeFullScreen())
  }
})

onUnmounted(() => {
  document.body.style.overflow = 'unset'
  document.removeEventListener('scroll', scrollFn, true)
  document.removeEventListener('fullscreenchange', () => document.fullscreenElement ? fullScreen() : closeFullScreen())
  document.removeEventListener('msfullscreenchange', () => document.msFullscreenElement ? fullScreen() : closeFullScreen())
  document.removeEventListener('mozfullscreenchange', () => document.mozFullScreen ? fullScreen() : closeFullScreen())
  document.removeEventListener('webkitfullscreenchange', () => document.webkitIsFullScreen ? fullScreen() : closeFullScreen())
})

const scroll = {x: 'undefined', y: 'undefined'}
const scrollFn = () => {
  if (typeof scroll.x == 'undefined') {
    scroll.x = state.differX = window.pageXOffset
    scroll.y = state.differY = window.pageYOffset
  }
}
// 全屏
const fullScreen = () => {
  state.activeKey == 0 ? displayArea.scrollTo(0, state.differY) && mindContent.scrollTo(state.differX, 0) : ''
  previewBox.style.paddingTop = '80px'
  displayArea.style.width = '100%'
  state.isFullScreen = true
  tabNavBox.style.top = '0px'
  const requestMethod = displayArea.requestFullScreen || displayArea.webkitRequestFullScreen || displayArea.mozRequestFullScreen
  requestMethod ? requestMethod.call(displayArea) : ''
}
// 退出全屏
const closeFullScreen = () => {
  state.activeKey == 0 ? window.scrollTo(0, state.differY) && mindContent.scrollTo(state.differX, 0) : window.scrollTo(0, 0)
  tabNavBox.style.padding = '0 20px'
  previewBox.style.paddingTop = '325px'
  state.isFullScreen = false
  tabNavBox.style.top = '344px'
  tabNavBox.style.boxShadow = 'unset'
  const exitMethod = document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen
  exitMethod ? exitMethod.call(document) : ''
}
// 切换左右键
const toggleMouse = type => {
  state.mouseType = type
  jmInner.style.userSelect = type === 'left' ? 'none' : 'unset'
}
// 定位中心
const locationGraph = () => {
  state.mindMapZoom = 100
  state.touchBoxScale = 1
  state.differX = 8750
  state.differY = 9400
  window.scrollTo(0, state.differY)
  displayArea.scrollTo(0, state.differY)
  mindContent.scrollTo(state.differX, 0)
}
// 重新加载
const refresh = () => {
  location.reload()
}
// 重置缩放
const resetScale = () => {
  state.mindMapZoom = 100
  state.touchBoxScale = 1
}
// 放大缩小
const changeZoom = type => {
  switch (type) {
    case 'add':
      if (state.mindMapZoom < 200) {
        state.mindMapZoom += 10
        state.touchBoxScale += 0.1
        mindMap.style.transform = `scale${state.touchBoxScale}`
      }
      break
    case 'minus':
      if (state.mindMapZoom > 50) {
        state.mindMapZoom -= 10
        state.touchBoxScale -= 0.1
        mindMap.style.transform = `scale${state.touchBoxScale}`
      }
      break
  }
}
// 导出文件
const exportFile = type => {
  state.showExport = false
  const elementWidth = state.jmActualWidth + state.hmargin * 2
  switch (type) {
    case 'png':
      return new Promise((resolve, reject) => {
        html2canvas(mindMap, {
          width: elementWidth
        }).then(cvs => {
          cvs.toBlob(blob => {
            const a = document.createElement('a')
            a.style.display = 'none'
            document.body.appendChild(a)
            const url = URL.createObjectURL(blob)
            a.setAttribute('href', url)
            a.setAttribute('download', `${route.query.url || state.urlData[0].url}.png`)
            a.click()
            URL.revokeObjectURL(url)
            document.body.removeChild(a)
            resolve(true)
          })
        }).catch(err => {
          reject(false)
        })
      })
    case 'pdf':
      html2canvas(mindMap, {
        width: elementWidth
      }).then(cvs => {
        const data = cvs.toDataURL('image/png', 1.0)
        const pdf = new JSPDF('I', 'px', [elementWidth, jmnodes.offsetHeight])
        pdf.addImage(data, 'PNG', 0, 0, elementWidth, jmnodes.offsetHeight)
        pdf.save(`${route.query.url || state.urlData[0].url}.pdf`)
      })
      break
  }
}
</script>

<style lang="less" scoped>
.backstage-container {
  min-height: 100vh;
  background: url("../assets/img/publicity/index/home_bg_normal.png") no-repeat;
  background-size: cover;
  min-width: 1100px;
  .backstage-content{
    text-align: center;
    padding-top: 180px;
    .home-logo {
      margin: 37px 0;
    }

    &:deep(.sub-title-row) {
      width: 408px;
      margin: 0 auto;
      box-sizing: border-box;
      display: flex;
      justify-content: space-between;

      h2 {
        font-size: 24px;
        margin-bottom: 0;
      }
    }

    &:deep(.hot-search) {
      width: 1000px;
      margin: 8px auto 0;
      display: flex;
      align-items: center;
      color: @text;
      font-size: 14px;
      img {
        margin-right: 8px;
      }

      span {
        padding-top: 2px;
      }

      .ant-row {
        padding-top: 2px;

        .hot-url-col {
          cursor: pointer;
        }
      }
    }
  }
}

.check-container {
  min-width: 1100px;
  min-height: 100vh;
  padding-top: 80px;

  &:deep(.search-content-box) {
    width: 100%;
    min-width: 1100px;
    padding: 0 20px;
    position: fixed;
    top: 80px;
    z-index: 3;
    background-color: #FFFFFF;
    .search-content-card {
      max-width: 1632px;
      margin: 0 auto;
      box-sizing: border-box;
      padding: 32px 0;

      .url-card-container {
        height: 200px;
        background: linear-gradient(227deg, #2F3C6A 0%, #0C1622 100%);
        border-radius: 8px;
        border: 1px solid #1B2739;
        padding: 32px 32px 25px;
        width: 100%;
        display: flex;

        .url-card-logo {
          width: 40px;
          height: 40px;
          min-width: 40px;
          min-height: 40px;
          border-radius: 50%;
          background-color: #FFFFFF;
        }

        .url-card-content {
          width: 540px;
          margin-left: 30px;

          h3 {
            color: #ffffff;
            font-size: 21px;
            font-weight: 600;
            line-height: 29px;
            text-align: left;
          }

          p {
            color: #ffffff;
            font-size: 14px;
            line-height: 20px;
            text-align: left;
          }

          .ant-divider {
            background-color: #636D7B;
            margin-bottom: 17px;
          }

          a {
            display: inline-block;
            color: #7F8EA6;
            float: right;

            &:hover {
              color: #90a1bb;
            }
          }
        }

        .ant-skeleton {
          .ant-skeleton-title {
            margin: 0;
          }

          .ant-skeleton-paragraph {
            margin-top: 15px;

            li {
              &:nth-last-child(1) {
                float: right;
              }
            }
          }
        }
      }

      .detect-card {
        height: 200px;
        margin-left: 24px;
        background: linear-gradient(226deg, #2559FF 0%, #2658FF 0%, #483CFF 53%, #7D74FF 100%);
        border-radius: 8px;
        box-sizing: border-box;
        padding: 16px 30px 30px;
        display: flex;
        justify-content: space-between;
        align-items: flex-end;
        overflow: hidden;

        a {
          display: inline-flex;
          align-items: flex-start;
          height: 100%;
          color: #ffffff;
        }

        .ant-progress {
          border: 6px solid #E3E4FF;
          box-sizing: border-box;
          border-radius: 50%;
          background-color: #ffffff;

          .ant-progress-inner {
            width: 128px !important;
            height: 128px !important;
          }

          .ant-progress-text {
            color: @danger;
            font-size: 36px;

            &:after {
              content: '安全检测分值';
              margin-top: 10px;
              color: @text;
              font-size: 12px;
              display: block;
            }

            span {
              font-size: 12px;
              margin-left: 1px;
            }
          }
        }

        .progress-loading {
          width: 140px;
          height: 140px;
          background-color: rgb(239, 244, 255);
          border: 12px solid #E3E4FF;
          border-radius: 50%;
          position: relative;
          overflow: hidden;
          flex: 1 0 140px;

          &:before {
            content: 'Loading...';
            position: absolute;
            top: 35%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #000000;
            font-size: 16px;
            font-family: sans-serif;
          }

          &:after {
            content: '';
            width: 280px;
            height: 280px;
            background-color: #ffffff;
            opacity: 0.8;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -100%);
            transform-origin: center;
            border-radius: 40%;
            animation: wave 3.5s linear infinite;
          }

          @keyframes wave {
            from {
              transform: translate(-50%, -100%) rotate(0deg);
            }
            to {
              transform: translate(-50%, -100%) rotate(360deg);
            }
          }
        }

        .detect-descript {
          color: #ffffff;
          width: 300px;
          height: 140px;
          padding-left: 30px;

          .ant-descriptions-header {
            .ant-descriptions-title {
              color: #ffffff;
              text-align: left;
            }
          }

          .ant-descriptions-view {
            .ant-descriptions-row {
              .ant-descriptions-item {
                .ant-descriptions-item-container {
                  .ant-descriptions-item-label {
                    color: #ffffff;
                    align-items: center;

                    img {
                      margin-right: 8px;
                    }

                    &:after {
                      display: none;
                    }
                  }
                }
              }
            }
          }
        }

        .ant-skeleton {
          .ant-skeleton-content {
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
          }
        }
      }
    }
  }

  &:deep(.display-area) {
    width: 100%;
    min-height: calc(100vh - 80px);
    overflow: auto;
    background-color: rgb(240, 242, 245);

    .ant-tabs-nav {
      margin-bottom: 0 !important;
    }

    .ant-tabs-nav-list {
      align-items: center;
    }

    .tab-nav-box {
      width: 100%;
      padding: 0 20px;
      position: fixed;
      top: 344px;
      left: 0;
      z-index: 3;
      background-color: #FFFFFF;
      min-width: 1100px;
      .tab-nav-content {
        max-width: 1632px;
        display: flex;
        justify-content: space-between;
        margin: 0 auto;
        background-color: #FFFFFF;

        .tab-operation {
          width: 100%;
          display: flex;
          align-items: center;
          justify-content: space-between;

          .ant-cascader-picker {
            width: 280px;
            background-color: #F7F7F7;

            .anticon-close-circle {
              svg {
                color: @text !important;
              }
            }
          }

          .tu-biao-area {
            display: flex;
            align-items: center;

            .percentage-num {
              width: 40px;
              display: inline-block;
              text-align: center;
              cursor: pointer;
              user-select: none;
            }

            .ant-divider {
              margin: 0 20px;
              border-color: @split-line;
            }
          }

          .share-area {
            img {
              cursor: pointer;
              vertical-align: middle;
              padding-right: 8px;
            }

            .share-btn {
              margin-left: 25px;
            }
          }
        }

        .tab-page-preview {
          border-radius: 18px;
          display: flex;
          align-items: center;
          margin-top: 7px;
          color: #fff;
          text-align: center;
          padding-bottom: 8px;

          i {
            margin-right: 35px;
          }
        }
      }
    }

    .mind-map-content {
      position: relative;
      overflow: auto;

      .mind-map-box {
        width: 20000px;
        height: 20000px;
        min-height: 500px;
        overflow: hidden;
        background-color: rgb(240, 242, 245);
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }

    .small-map-container {
      width: 300px;
      height: 170px;
      background-color: #FFFFFF;
      position: fixed;
      bottom: 15px;
      right: 15px;
      box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.08);
      border-radius: 8px;
      z-index: 100;
      overflow: hidden;

      #small-map {
        width: 100%;
        height: 100%;
      }

      #view-port {
        border: 1px solid @primary;
        position: absolute;
        z-index: 2;
        cursor: move;
        display: inline-block;
      }
    }

    .preview-box {
      display: flex;
      justify-content: center;
      padding-top: 325px;
    }
  }

  i.img-icon {
    width: 28px;
    height: 28px;
    display: inline-block;
    overflow: hidden;
    cursor: pointer;
    vertical-align: middle;

    img {
      position: relative;
      border-right: 28px solid transparent;
    }

    &:hover {
      img {
        filter: drop-shadow(@primary 28px 0px);
        left: -28px;
      }
    }
  }

  &:deep(.cascader-box) {
    max-width: 650px;
    margin: 25px auto 40px;
    display: flex;
    justify-content: space-between;

    .cascader-select {
      max-width: 650px;
      line-height: 0;
      text-align: left;

      .cascader-title {
        font-weight: bold;
        font-size: 16px;
        color: @primary;
      }
    }
  }

  &:deep(.ant-tabs) {
    .ant-tabs-nav {
      background-color: #FFFFFF;

      &:before {
        border: none;
      }

      .ant-tabs-nav-list {
        width: 500px;
        margin: 0 auto;
        box-sizing: border-box;

        .ant-tabs-nav {
          margin-bottom: 50px;
        }

        .ant-tabs-tab-btn {
          text-align: center;

          div {
            font-size: 15px;
            font-weight: bold;
            color: @text;
            line-height: 33px;
            letter-spacing: 1px;
          }
        }

        .ant-tabs-tab-btn-active {
          div {
            color: @primary;
          }
        }
      }
    }
  }
}

@media screen and (max-width: 1260px) {
  .search-content-box{
    .search-content-card{
      .url-card-container{
        padding: 35px 25px 25px!important;
      }
      .detect-card{
        margin-left: 20px!important;
        padding: 16px 20px 30px!important;
      }
    }
  }
  &:deep(.ant-tabs) {
    .ant-tabs-nav {
      .ant-tabs-nav-list {
        width: 300px !important;
      }
    }
  }

  &:deep(.detect-descript) {
    padding-left: 10px !important;

    .ant-descriptions-item-label {
      font-size: 12px;
    }
  }
}
</style>

<style lang="less">
.export-menu,
.share-menu {
  max-width: 320px;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 2px 2px 10px 0 rgba(153, 153, 153, 0.23);

  .ant-popover-content {
    .ant-btn {
      width: 260px;
      height: 40px;
    }

    .ant-popover-inner {
      padding: 20px 30px 35px;

      .ant-popover-title {
        border-bottom: none;
        font-size: 16px;
        color: @primary;
        padding: 0;
        min-height: unset;
        margin-bottom: 25px;
      }

      .ant-popover-inner-content {
        padding: 0;

        .ant-btn-primary {
          margin-top: 15px;
        }
      }
    }
  }
}

.export-menu {
  padding-top: 1px;

  .ant-popover-content {
    .ant-popover-inner {
      .ant-popover-inner-content {
        .export-btn-box {
          display: flex;
          flex-direction: column;

          .ant-btn {
            img {
              margin-right: 10px;
            }

            &:nth-of-type(1) {
              color: @primary;
            }
          }
        }
      }
    }
  }
}

.share-menu {
  padding-top: 3px;

  .ant-popover-content {
    .ant-popover-inner {
      .ant-popover-inner-content {
        p {
          color: @content;
        }

        .ant-descriptions {
          .ant-descriptions-view {
            .ant-descriptions-row {
              .ant-descriptions-item {
                padding-bottom: 0;

                .ant-descriptions-item-container {
                  align-items: center;

                  .ant-descriptions-item-content {
                    padding: 4px 15px;
                    background-color: @bgc-color;
                    border-radius: 5px;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

.text-tip {
  .ant-tooltip-content {
    .ant-tooltip-inner {
      min-height: unset;
      padding-top: 2px;
      padding-bottom: 2px;
      font-size: 12px;
    }
  }
}

.jsmind-inner {
  overflow: unset;
  width: unset;
  height: unset;

  jmnodes.theme-custom {
    jmnode {
      border: 1px solid;
      color: @text;
      padding: 8px 20px;
      box-shadow: unset;
      max-width: 600px;
      font-size: 14px;

      a {
        -webkit-user-drag: none;
        border-bottom: 1px solid;
      }
    }

    jmnode.root {
      font-size: 16px;
      color: #F0F0FF;
      border-color: @primary;
      background-color: @primary;
      padding: 8px 15px;
      font-weight: 600;
    }

    jmexpander {
      display: flex;
      align-items: center;
      justify-content: center;
      line-height: unset;
      margin: 2px;
    }
  }
}
</style>
